// 中介者模式 - 迪米特法则
// 泡泡堂
const players = [];

const playerDirector = (function() {
    const player = {};
    const operations = {};

    operations.addPlayer = function (player) {
        const teamColor = player.teamColor;
        players[teamColor] = players[teamColor] || [];
        players[teamColor].push(player);
    }

    operations.removePlayer = function(player) {
        const teamColor = player.teamColor;
        const teamPlayers = players[teamColor] || [];
        for (let i = teamPlayers.length - 1; i >= 0; i--) {
            if (teamPlayers[i] === player) {
                teamPlayers.splice(i, 1)
            }
        }
    }

    operations.changeTeam = function (player, newTeamColor) {
        operations.removePlayer(player);
        player.teamColor = newTeamColor;
        operations.addPlayer(player);
    }

    operations.playerDied = function (player) {
        const teamColor = player.teamColor;
        const teamPlayers = players[teamColor] || [];

        const all_dead = teamPlayers.every(i => i.state === 'died')
        if (all_dead) {
            teamPlayers.forEach((i) => {
                i.lose();
            })
        }

        for (let color in players) {
            if (color !== teamColor) {
                const teamPlayers = players[teamColor];
                teamPlayers.forEach((i) => {
                    i.win();
                })
            }
        }
    }

    const receiveMessage = function () {
        const message = Array.prototype.shift.call(arguments);
        operations[message].apply(this, arguments);
    }

    return {
        receiveMessage
    }
})();

function Player(name, teamColor) {
    this.name = name;
    this.state = 'alive';
    this.teamColor = teamColor;
}

Player.prototype.win = function() {
    console.log(`Winner: ${this.name}`);
}

Player.prototype.lose = function () {
    console.log(`loser: ${this.name}`);
}

Player.prototype.die = function () {
    this.state = 'die';
    playerDirector.receiveMessage('player died', this);
}

Player.prototype.remove = function() {
    playerDirector.receiveMessage('player reomve', this);
}

Player.prototype.changeTeam = function() {
    playerDirector.receiveMessage('player change team', this);
}

const playerFactory = function(name, teamColor) {
    const newPlayer = new Player(name, teamColor);
    playerDirector.receiveMessage('add player', this);
    return newPlayer;
}

const player1 = playerFactory('playerA', 'red');
const player2 = playerFactory('plaberB', 'red');
const player3 = playerFactory('plaberC', 'red');
const player4 = playerFactory('plaberD', 'red');
const player5 = playerFactory('plaberE', 'red');
const player6 = playerFactory('plaberF', 'red');
const player7 = playerFactory('plaberG', 'red');
const player8 = playerFactory('plaberH',  'red');

// 装饰者
const obj = {
    name: 'seven',
    address: '深圳'
}
obj.address = obj.address + '福田'

// const Plane = function() {}
// Plane.prototype.fire = function () {
//     console.log('发射普通子弹');
// }

// const MissileDecorator = function (plane) {
//     this.plane = plane
// }

// MissileDecorator.prototype.fire = function () {
//     this.plane.fire();
//     console.log('发射导弹');
// }

// const AtomDecorator = function (plane) {
//     this.plane = plane;
// }

// AtomDecorator.prototype.fire = function () {
//     this.plane.fire();
//     console.log('发射原子弹');
// }

// let plane = new Plane();
// plane = new MissileDecorator(plane);
// plane = new AtomDecorator(plane);

const plane = {
    fire: function () {
        console.log('发射普通子弹');
    }
}

const missileDecorator = function () {
    console.log('发射导弹');
}

const atomDecorator = function () {
    console.log('原子弹');
}

const fire1 = plane.fire;
plane.fire = function () {
    fire1();
    missileDecorator();
}

const fire2 = plane.fire;
plane.fire = function () {
    fire2();
    atomDecorator();
}

const _getElementsById = document.getElementById;
document.getElementById = function () {
    alert('1');
    return _getElementsById.apply(document, arguments);
}

// AOP
// Function.before/Function.after
Function.prototype.before = function (beforeFn) {
    const _self = this;
    return function () {
        beforeFn.apply(this, arguments);
        return _self.apply(this, arguments);
    }
}

Function.prototype.after = function (afterFn) {
    const _self = this;
    return function () {
        const ret = _self.apply(this, arguments);
        afterFn.apply(this, arguments);
        return ret;
    }
}

window.onload = function () {
    alert('1');
}

window.onload = (window.onload || function () {}).after(function() {
    alert('2');
}).after(function () {
    alert('3');
})

// 状态模式 - 允许一个对象在其内部状态改变时改变他的行为，对象看起来似乎修改了他的类；
const Light = function () {
    this.button = null;
    this.offLightState = new OffLightState(this);
    this.weakLightState = new WeakLightState(this);
    this.strongLightState = new StrongLightState(this);
    this.superStrongLightState = new SuperSrongLightState(this);
}

Light.prototype.init = function () {
    const button = document.createElement('button');
    const self = this;
    button.innerHTML = '开关';
    this.button = document.body.appendChild(button);
    this.currState = this.offLightState;
    this.button.onclick = function () {
        self.currState.buttonWasPressed();
    }
}

Light.prototype.setState = function (newState) {
    this.currState = newState
}

const OffLightState = function (light) {
    this.light = light;
}

offLightState.prototype.buttonWasPressed = function () {
    console.log('弱光');
    this.light.setState(this.light.weakLightState);
}

const WeakLightState = function (light) {
    this.light = light;
}

WeakLightState.prototype.buttonWasPressed = function () {
    console.log('强光');
    this.light.setState(this.light.strongLightState);
}

const StrongLightState = function (light) {
    this.light = light;
}

StrongLightState.prototype.buttonWasPressed = function () {
    console.log('超强灯');
    this.light.setState(this.light.superStrongLightState);
}

const SuperSrongLightState = function (light) {
    this.light = light;
}

SuperSrongLightState.prototype.buttonWasPressed = function () {
    console.log('关灯');
    this.light.setState(this.light.offLightState);
}

const light = new Light();
light.init();





// 文件上传
window.external.upload = function (state) {
    console.log(state); // sign/uploading/done/error
}

const plugin = (function() {
    const plugin = document.createElement('embed');
    plugin.style.display = 'none';
    plugin.type = 'application/json';
    plugin.sign = function() {
        console.log('sign');
    }
    plugin.uploading = function () {
        console.log('uploading');
    }
    plugin.del = function () {
        console.log('del');
    }
    plugin.done = function () {
        console.log('done');
    }
    document.body.appendChild(plugin);
    return plugin;
})();

// const Upload = function (fileName) {
//     this.plugin = plugin;
//     this.fileName = fileName;
//     this.button1 = null;
//     this.button2 = null;
//     this.state = 'sign';
// }

const Upload = function (fileName) {
    this.plugin = plugin;
    this.fileName = fileName;
    this.button1 = null;
    this.button2 = null;
    this.signState = new SignState(this);
    this.uploadingState = new UploadingState(this);
    this.pauseState = new PauseState(this);
    this.doneState = new DoneState(this);
    this.errorState = new ErrorState(this);
    this.currState = this.signState;
}

Upload.prototype.init = function () {
    const self = this;
    this.dom = document.createElement('div');
    this.dom.innerHTML = `
        <span>文件名称: ${this.fileName}</span>
        <button data-action="button1">扫描中</button>
        <button data-action="button2">删除</button>
    `;
    document.body.appendChild(this.dom);
    this.button1 = document.querySelector('[data-action="button1"]');
    this.button2 = document.querySelector('[data-action="button2"]');
    this.bindEvent();
}

// Upload.prototype.bindEvent = function () {
//     const self = this;
//     this.button1.onclick = function () {
//         if (self.state === 'sign') {
//             console.log('sign, invalid');
//         } else if (self.state === 'uploading') {
//             console.log('上传中');
//             this.changeState('pause');
//         } else if (self.state === 'pause') {
//             console.log('暂停');
//             this.changeState('uploading');
//         } else if (self.state === 'done') {
//             console.log('上传完成');
//         } else if (self.state === 'error') {
//             console.log('报错');
//         }
//     }

//     this.button2.onclick = function () {
//         if (self.state === 'done' || self.state === 'error' || self.state === 'pause') {
//             self.changeState('del');
//         } else if (self.state === 'sign' || self.state === 'uploading') {
//             return;
//         }
//     }
// }

Upload.prototype.bindEvent = function () {
    const self = this;
    this.button1.onclick = function() {
        self.currState.clickHandler1();
    }
    this.button2.onclick = function () {
        self.currState.clickHandler2();
    }
}

// Upload.prototype.changeState = function (state) {
//     switch (state) {
//         case 'sign':
//             this.plugin.sign();
//             this.button1.innerHTML = '扫描中, 其他操作无效';
//             break;
//         case 'uploading':
//             this.plugin.uploading();
//             this.button1.innerHTML = '上传 点击暂停';
//             break;
//         case 'pause':
//             this.plugin.pause();
//             this.button1.innerHTML = '已暂停，点击继续上传';
//             break;
//         case 'done':
//             this.plugin.done();
//             this.button1.innerHTML = '上传完成';
//             break;
//         case 'error':
//             this.button1.innerHTML = '失败'
//             break;
//         case 'del':
//             this.plugin.del();
//             this.dom.parentNode.removeChild(this.dom);
//             console.log('已删除');
//             break;
//     }
// }

Upload.prototype.sign = function () {
    this.plugin.sign();
    this.currState = this.signState;
}

Upload.prototype.uploading = function () {
    this.button1.innerHTML = 'uploading, click to pause';
    this.plugin.uploading();
    this.currState = this.signState;
}

Upload.prototype.pause = function () {
    this.button1.innerHTML = 'paused, click to upload';
    this.plugin.pause();
    this.currState = this.signState;
}

Upload.prototype.done = function () {
    this.button1.innerHTML = 'done';
    this.plugin.done();
    this.currState = this.signState;

}

Upload.prototype.error = function () {
    this.button1.innerHTML = 'error';
    this.currState = this.signState;
}

Upload.prototype.del = function () {
    this.plugin.del();
    this.dom.parentNode.removeChild(this.dom);
}

const StateFactory = (function() {
    const State = function() {}
    State.prototype.clickHandler1 = function() {
        throw new Error('子类必须重写父类的clickHandler1');
    }
    State.prototype.clickHandler2 = function() {
        throw new Error('子类必须重写父类的clickHandler2');
    }

    return function (param) {
        const F = function(uploadObj) {
            this.uploadObj = uploadObj;
        }
        F.prototype = new State();
        for (let i in param) {
            F.prototype[i] = param[i]
        }
    }
})()

const SignState = StateFactory({
    clickHandler1: function() {
        console.log('signing');
    },
    clickHandler2: function () {
        console.log('uploading, can not del');
    }
})

const UploadingState = StateFactory({
    clickHandler1: function() {
        this.uploadObj.pause();
    },
    clickHandler2: function () {
        console.log('uploading, can not del');
    }
})

const PauseState = StateFactory({
    clickHandler1: function() {
        this.uploadObj.uploading();
    },
    clickHandler2: function () {
        this.uploadObj.del();
    }
})

const DoneState = StateFactory({
    clickHandler1: function() {
        console.log('done');
    },
    clickHandler2: function () {
        this.uploadObj.del();
    }
});

const ErrorState = StateFactory({
    clickHandler1: function() {
        console.log('error');
    },
    clickHandler2: function () {
        this.uploadObj.del();
    }
});



